/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is Forte for Java, Community Edition. The Initial * Developer of the Original Code is Sun Microsystems, Inc. Portions * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved. */ package org.openide.text; import java.io.*; import java.lang.ref.WeakReference; import java.util.*; import javax.swing.text.Position; import javax.swing.text.StyledDocument; import javax.swing.text.BadLocationException; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.openide.loaders.DataObject; import org.openide.cookies.EditorCookie; /** Reference to one position in a document. * This position is held as an integer offset, or as a {@link Position} object. * There is also support for serialization of positions. * * @author Petr Hamernik */ public final class PositionRef extends Object implements Serializable { static final long serialVersionUID = -4931337398907426948L; /** Which type of position is currently holded - int X Position */ transient private Manager.Kind kind; /** Manager for this position */ private Manager manager; /** insert after? */ private boolean insertAfter; /** Creates new <code>PositionRef</code> using the given manager at the specified * position offset. * @param manager manager for the position * @param offset - position in the document * @param bias the bias for the position */ PositionRef (Manager manager, int offset, Position.Bias bias) { this (manager, manager.new OffsetKind (offset), bias); } /** Creates new <code>PositionRef</code> using the given manager at the specified * line and column. * @param manager manager for the position * @param line line number * @param column column number * @param bias the bias for the position */ PositionRef (Manager manager, int line, int column, Position.Bias bias) { this (manager, manager.new LineKind (line, column), bias); } /** Constructor for everything. * @param manager manager that we are refering to * @param kind kind of position we hold * @param bias bias for the position */ private PositionRef (Manager manager, Manager.Kind kind, Position.Bias bias) { this.manager = manager; this.kind = kind; insertAfter = (bias == Position.Bias.Backward); init (); } /** Initialize variables after construction and after deserialization. */ private void init() { kind = manager.addPosition(this); } /** Writes the manager and the offset (int). */ private void writeObject(ObjectOutputStream out) throws IOException { out.writeBoolean (insertAfter); out.writeObject (manager); kind.write (out); } /** Reads the manager and the offset (int). */ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { insertAfter = in.readBoolean (); manager = (Manager)in.readObject(); kind = manager.readKind (in); init (); } /** @return the appropriate manager for this position ref. */ public EditorSupport getEditorSupport () { return manager.getEditorSupport (); } /** @return the bias of the position */ public Position.Bias getPositionBias() { return insertAfter ? Position.Bias.Backward : Position.Bias.Forward; } /** @return the position as swing.text.Position object. * @exception IOException when an exception occured during reading the file. */ public Position getPosition() throws IOException { synchronized (manager.getEditorSupport ().getLock ()) { manager.getEditorSupport ().openDocument (); Manager.PositionKind p = (Manager.PositionKind)kind; return p.pos; } } /** @return the position as offset index in the file. */ public int getOffset() { return kind.getOffset (); } /** Get the line number where this position points to. * @return the line number for this position * @throws IOException if the document could not be opened to check the line number */ public int getLine() throws IOException { return kind.getLine (); } /** Get the column number where this position points to. * @return the column number within a line (counting starts from zero) * @exception IOException if the document could not be opened to check the column number */ public int getColumn() throws IOException { return kind.getColumn (); } public String toString() { return "Pos[" + getOffset () + "]"; // NOI18N } /** This class is responsible for the holding the Document object * and the switching the status of PositionRef (Position X offset) * objects which depends to this manager. * It has one abstract method for the creating the StyledDocument. */ static final class Manager extends Object implements Serializable { /** List of the WeakReferences to the PositionRef objects * created for this manager. * @associates WeakReference */ transient LinkedList positions; /** support for the editor */ transient private EditorSupport support; /** the document for this manager or null if the manager is not in memory */ transient private StyledDocument doc; static final long serialVersionUID =-4374030124265110801L; /** Creates new manager * @param supp support to work with */ public Manager(EditorSupport supp) { support = supp; init(); } /** Initialize the variables to the default values. */ protected void init() { positions = new LinkedList(); } /** Reads the object and initialize */ private void readObject (ObjectInputStream in) throws IOException, ClassNotFoundException { DataObject obj = (DataObject) in.readObject(); support = (EditorSupport) obj.getCookie(EditorSupport.class); if (support == null) { //PENDING - what about now ? does exist better way ? throw new IOException(); } } final Object readResolve () { return support.getPositionManager (); } private void writeObject(ObjectOutputStream out) throws IOException { out.writeObject(support.findDataObject()); } /** @return the styled document or null if the document is not loaded. */ public EditorSupport getEditorSupport () { return support; } /** Converts all positions into document one. */ void documentOpened (StyledDocument doc) { this.doc = doc; ListIterator it = positions.listIterator(); while (it.hasNext()) { WeakReference ref = (WeakReference) it.next(); PositionRef pos = (PositionRef) ref.get(); if (pos == null) it.remove(); else { pos.kind = pos.kind.toMemory (pos.insertAfter); } } } /** Closes the document and switch all positionRefs to the offset (int) * holding status (Position objects willbe forgotten. */ void documentClosed () { Iterator it = ((Collection)positions.clone ()).iterator(); while (it.hasNext()) { WeakReference ref = (WeakReference) it.next(); PositionRef pos = (PositionRef) ref.get(); if (pos == null) positions.remove(ref); else { pos.kind = pos.kind.fromMemory (); } } doc = null; } /** Adds the position to this manager. */ Kind addPosition(PositionRef pos) { synchronized (getEditorSupport ().getLock ()) { positions.add(new WeakReference(pos)); if (doc != null) { return pos.kind.toMemory (pos.insertAfter); } else { return pos.kind; } } } // // Kinds // /** Loads the kind from the stream */ private Kind readKind (DataInput is) throws IOException { int offset = is.readInt (); int line = is.readInt (); int column = is.readInt (); if (offset == -1) { // line and column must be valid return new LineKind (line, column); } if (line == -1 || column == -1) { // offset kind return new OffsetKind (offset); } // out of memory representation return new OutKind (offset, line, column); } /** Base kind with all methods */ private abstract class Kind extends Object { /** Offset */ public abstract int getOffset (); /** Get the line number */ public abstract int getLine() throws IOException; /** Get the column number */ public abstract int getColumn() throws IOException; /** Writes the kind to stream */ public abstract void write (DataOutput os) throws IOException; /** Converts the kind to representation in memory */ public PositionKind toMemory (boolean insertAfter) { // try to find the right position Position p; try { p = NbDocument.createPosition (doc, getOffset (), insertAfter ? Position.Bias.Forward : Position.Bias.Backward); } catch (BadLocationException e) { p = doc.getEndPosition (); } return new PositionKind (p); } /** Converts the kind to representation out from memory */ public Kind fromMemory () { return this; } } /** Kind for representing position when the document is * in memory. */ private final class PositionKind extends Kind { /** position */ private Position pos; /** Constructor */ public PositionKind (Position pos) { this.pos = pos; } /** Offset */ public int getOffset () { return pos.getOffset (); } /** Get the line number */ public int getLine() { return NbDocument.findLineNumber(doc, getOffset()); } /** Get the column number */ public int getColumn() { return NbDocument.findLineColumn(doc, getOffset()); } /** Writes the kind to stream */ public void write (DataOutput os) throws IOException { os.writeInt (getOffset ()); os.writeInt (getLine ()); os.writeInt (getColumn ()); } /** Converts the kind to representation in memory */ public PositionKind toMemory (boolean insertAfter) { return this; } /** Converts the kind to representation out from memory */ public Kind fromMemory () { return new OutKind (this); } } /** Kind for representing position when the document is * out from memory. There are all infomation about the position, * including offset, line and column. */ private final class OutKind extends Kind { private int offset; private int line; private int column; /** Constructs the out kind from the position kind. */ public OutKind (PositionKind kind) { this.offset = kind.getOffset (); this.line = kind.getLine (); this.column = kind.getColumn (); } /** Constructs the out kind. */ OutKind (int offset, int line, int column) { this.offset = offset; this.line = line; this.column = column; } /** Offset */ public int getOffset () { return offset; } /** Get the line number */ public int getLine() { return line; } /** Get the column number */ public int getColumn() { return column; } /** Writes the kind to stream */ public void write (DataOutput os) throws IOException { os.writeInt (offset); os.writeInt (line); os.writeInt (column); } } // OutKind /** Kind for representing position when the document is * out from memory. Represents only offset in the document. */ private final class OffsetKind extends Kind { private int offset; /** Constructs the out kind from the position kind. */ public OffsetKind (int offset) { this.offset = offset; } /** Offset */ public int getOffset () { return offset; } /** Get the line number */ public int getLine() throws IOException { return NbDocument.findLineNumber(getEditorSupport().openDocument(), offset); } /** Get the column number */ public int getColumn() throws IOException { return NbDocument.findLineColumn (getEditorSupport().openDocument(), offset); } /** Writes the kind to stream */ public void write (DataOutput os) throws IOException { os.writeInt (offset); os.writeInt (-1); os.writeInt (-1); } } /** Kind for representing position when the document is * out from memory. Represents only line and column in the document. */ private final class LineKind extends Kind { private int line; private int column; /** Constructor. */ public LineKind (int line, int column) { this.line = line; this.column = column; } /** Offset */ public int getOffset () { try { StyledDocument doc = getEditorSupport().openDocument(); return NbDocument.findLineOffset (doc, line) + column; } catch (IOException e) { // what to do? hopefully unlikelly return 0; } } /** Get the line number */ public int getLine() throws IOException { return line; } /** Get the column number */ public int getColumn() throws IOException { return column; } /** Writes the kind to stream */ public void write (DataOutput os) throws IOException { os.writeInt (-1); os.writeInt (line); os.writeInt (column); } /** Converts the kind to representation in memory */ public PositionKind toMemory (boolean insertAfter) { // try to find the right position Position p; try { p = NbDocument.createPosition (doc, NbDocument.findLineOffset (doc, line) + column, insertAfter ? Position.Bias.Forward : Position.Bias.Backward); } catch (BadLocationException e) { p = doc.getEndPosition (); } return new PositionKind (p); } } } } /* * Log * 27 src-jtulach1.26 1/15/00 Daniel Prusa serialization fixed * 26 src-jtulach1.25 1/13/00 Ian Formanek NOI18N * 25 src-jtulach1.24 10/22/99 Ian Formanek NO SEMANTIC CHANGE - Sun * Microsystems Copyright in File Comment * 24 src-jtulach1.23 8/17/99 Ian Formanek Generated serial version * UID * 23 src-jtulach1.22 6/8/99 Ian Formanek ---- Package Change To * org.openide ---- * 22 src-jtulach1.21 5/14/99 Jaroslav Tulach Bugfixes. * 21 src-jtulach1.20 5/5/99 Petr Hamernik getPositionBias() method * added * 20 src-jtulach1.19 4/20/99 Petr Hamernik small mistake fixed * 19 src-jtulach1.18 4/20/99 Jaroslav Tulach Updated to work with * position biases. * 18 src-jtulach1.17 4/9/99 David Simonek bugfix #1429 * 17 src-jtulach1.16 3/11/99 Jaroslav Tulach * 16 src-jtulach1.15 3/10/99 Jaroslav Tulach Kinds do not use * getDocument * 15 src-jtulach1.14 3/9/99 Jaroslav Tulach Everything is * implemented. * 14 src-jtulach1.13 3/8/99 Jaroslav Tulach * 13 src-jtulach1.12 3/8/99 Jaroslav Tulach Bundles. * 12 src-jtulach1.11 2/26/99 Jesse Glick [JavaDoc] * 11 src-jtulach1.10 2/19/99 Petr Hamernik * 10 src-jtulach1.9 2/19/99 Petr Hamernik changes with * Position.Bias * 9 src-jtulach1.8 2/17/99 Petr Hamernik * 8 src-jtulach1.7 2/11/99 Jesse Glick get{Line,Column}() were * both getting column, and were (gratuitously?) catching & ignoring * IOExceptions. * 7 src-jtulach1.6 2/10/99 Jesse Glick [JavaDoc] * 6 src-jtulach1.5 2/8/99 Petr Hamernik * 5 src-jtulach1.4 2/3/99 Jaroslav Tulach * 4 src-jtulach1.3 2/2/99 Jaroslav Tulach * 3 src-jtulach1.2 1/29/99 Petr Hamernik * 2 src-jtulach1.1 1/29/99 Petr Hamernik * 1 src-jtulach1.0 1/29/99 Petr Hamernik * $ */